import cv2
import mediapipe as mp
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import serial

# 由于 Labview 调用命令行 无法实时输出当前情况
# 采取读取文件信息的方案来解决
file_path = r'C:\Users\21412\Desktop\项目\temp.txt'

# 配置串口参数
try:
    ser = serial.Serial(
        port='COM3',  # 根据实际情况修改串口号
        baudrate=9600,
        timeout=1
    )
    print('串口已打开')
except serial.SerialException as e:
    print(f'无法打开串口: {e}')
    ser = None


def put_chinese_text(img, text, position, font_path, font_size, color=(0, 0, 255)):
    """
    在图像上绘制中文文本
    :param img: cv2 图像
    :param text: 要绘制的中文文本
    :param position: 文本位置 (x, y)
    :param font_path: 字体文件路径
    :param font_size: 字体大小
    :param color: 文本颜色，格式为 (B, G, R)
    :return: 绘制了中文文本的图像
    """
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    pil_img = Image.fromarray(img)
    draw = ImageDraw.Draw(pil_img)
    font = ImageFont.truetype(font_path, font_size)
    draw.text(position, text, font=font, fill=color)
    img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
    return img


class HandDetector:
    def __init__(self):
        self.handsData = None
        self.hand_detector = mp.solutions.hands.Hands(static_image_mode=False, max_num_hands=2)
        self.drawer = mp.solutions.drawing_utils
        self.last_gesture = None
        self.led_status = 'OFF'

    def find_hands(self, img):
        """找到手并连线"""
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.handsData = self.hand_detector.process(img_rgb)
        if self.handsData.multi_hand_landmarks:
            for hand_landmarks in self.handsData.multi_hand_landmarks:
                self.drawer.draw_landmarks(img, hand_landmarks, mp.solutions.hands.HAND_CONNECTIONS)

    # 寻找特征来判断手势
    def find_gesture(self, img):
        ans = ''
        # 使用绝对字体路径
        font_path = 'C:/Windows/Fonts/simhei.ttf'
        font_size = 30
        if self.handsData.multi_hand_landmarks:
            for hand_landmarks in self.handsData.multi_hand_landmarks:
                p0_x = hand_landmarks.landmark[0].x
                p0_y = hand_landmarks.landmark[0].y
                p5_x = hand_landmarks.landmark[5].x
                p5_y = hand_landmarks.landmark[5].y
                p8_x = hand_landmarks.landmark[8].x
                p8_y = hand_landmarks.landmark[8].y
                p12_x = hand_landmarks.landmark[12].x
                p12_y = hand_landmarks.landmark[12].y
                dis_0_5 = ((p0_x - p5_x) ** 2 + (p0_y - p5_y) ** 2) ** 0.5
                base = dis_0_5 / 0.8
                dis_0_8 = ((p0_x - p8_x) ** 2 + (p0_y - p8_y) ** 2) ** 0.5

                

                dis_0_12 = ((p0_x - p12_x) ** 2 + (p0_y - p12_y) ** 2) ** 0.5

                p16_x = hand_landmarks.landmark[16].x
                p16_y = hand_landmarks.landmark[16].y
                dis_0_16 = ((p0_x - p16_x) ** 2 + (p0_y - p16_y) ** 2) ** 0.5

                p20_x = hand_landmarks.landmark[20].x
                p20_y = hand_landmarks.landmark[20].y
                dis_0_20 = ((p0_x - p20_x) ** 2 + (p0_y - p20_y) ** 2) ** 0.5

                if dis_0_8 > base > dis_0_16 and dis_0_12 > base:
                    ans = '剪刀'
                elif dis_0_8 > base and dis_0_12 > base and dis_0_16 > base and dis_0_20 > base:
                    ans = '布'
                elif dis_0_8 < base and dis_0_12 < base and dis_0_16 < base and dis_0_20 < base:
                    ans = '石头'

                if ans != self.last_gesture:
                    if ans == '布':
                        if ser and ser.is_open:
                            ser.write(b'on')
                            self.led_status = 'ON'
                    elif ans == '石头':
                        if ser and ser.is_open:
                            ser.write(b'off')
                            self.led_status = 'OFF'
                    self.last_gesture = ans
        else:
            ans = '未知手势'

        print(ans)
        img = put_chinese_text(img, ans, (20, 50), font_path, font_size)
        img = put_chinese_text(img, f'LED is {self.led_status}', (20, 100), font_path, font_size)
        with open(file_path, "w", buffering=1) as f:  # 行缓冲模式
            f.write(ans)

        return img


cap = cv2.VideoCapture(0)

handDetector = HandDetector()

while True:
    ret, img = cap.read()
    img = cv2.flip(img, 1)
    if ret:
        handDetector.find_hands(img)
        img = handDetector.find_gesture(img)

    cv2.imshow('img', img)
    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

if ser and ser.is_open:
    ser.close()
    print('串口已关闭')
